import * as Cesium from 'cesium'

/**
 *
 * 笛卡尔坐标系转WGS84坐标系
 * @param {object} point 点,笛卡尔坐标{x:x,y:y,z:z}
 * @returns {object} -lat: lat, lng: lng, alt: alt
 * @function Cartesian3_to_WGS84
 * @memberof Coordinate
 */
export const Cartesian3_to_WGS84 = function (point) {
  var cartesian3 = new Cesium.Cartesian3(point.x, point.y, point.z);
  var cartographic = Cesium.Cartographic.fromCartesian(cartesian3);
  var lat = Cesium.Math.toDegrees(cartographic.latitude);
  var lng = Cesium.Math.toDegrees(cartographic.longitude);
  var alt = cartographic.height;
  return {
    lat: lat,
    lng: lng,
    alt: alt
  }
}

// 获取视角高
export const getPerspectiveHeight = function (viewer, cartesian2) {
  let cartesian = viewer.scene.globe.pick(viewer.camera.getPickRay(cartesian2), viewer.scene);
  let he = Math.sqrt(
    viewer.scene.camera.positionWC.x * viewer.scene.camera.positionWC.x +
    viewer.scene.camera.positionWC.y * viewer.scene.camera.positionWC.y +
    viewer.scene.camera.positionWC.z * viewer.scene.camera.positionWC.z
  )
  let he2 = Math.sqrt(
    cartesian.x * cartesian.x + cartesian.y * cartesian.y + cartesian.z * cartesian.z
  )
  return he - he2
}

/**
 *
 * WGS84坐标系转笛卡尔坐标系
 * @param {object} point 点,笛卡尔坐标{lat: lat, lng: lng, alt: alt}
 * @returns {object} - x:x,y:y,z:z
 * @function WGS84_to_Cartesian3
 * @memberof Coordinate
 */
export const WGS84_to_Cartesian3 = function (point) {
  var car33 = Cesium.Cartesian3.fromDegrees(point.lng, point.lat, point.alt);
  var x = car33.x;
  var y = car33.y;
  var z = car33.z;
  return {
    x: x,
    y: y,
    z: z,
  }
}

/**
 * 屏幕坐标转笛卡尔坐标，考虑球面、地形，三维模型
 * @param {object} viewer viewer
 * @param {object} cartesian2 屏幕坐标
 * @memberof Coordinate
 */
export const screenToCartesian = function (viewer, cartesian2) {
  let cartesian3 = viewer.scene.pickPosition(cartesian2)
  return cartesian3
}

/**
 * 屏幕坐标转笛卡尔坐标，考虑球面、地形，不考虑三维模型
 * @param {object} viewer viewer
 * @param {object} cartesian2 屏幕坐标
 * @memberof Coordinate
 */
export const screenToCartesianTerrain = function (viewer, cartesian2) {
  let ray = viewer.camera.getPickRay(cartesian2);
  let cartesian = viewer.scene.globe.pick(ray, viewer.scene);
  return cartesian
}

/**
 * 屏幕坐标转笛卡尔坐标，只考虑球面
 * @param {object} viewer viewer
 * @param {object} cartesian2 屏幕坐标
 * @memberof Coordinate
 */
export const screenToCartesianEllipsoid = function (viewer, cartesian2) {
  let cartesian3 = viewer.camera.pickEllipsoid(cartesian2, viewer.scene.globe.ellipsoid)
  return cartesian3
}

/**
 * 屏幕坐标转墨卡托坐标
 * @param {object} viewer viewer
 * @param {object} windowPosition 屏幕坐标
 * @function screenToMercator
 * @memberof Coordinate
 */
export const screenToMercator = function (viewer, windowPosition) {
  let cartesian = this.screenToCartesian(viewer, windowPosition);
  // 世界坐标转换为投影坐标
  var cartographic = Cesium.Cartographic.fromCartesian(cartesian);
  let viewPointWebMercator = this.cartographicToMercatorCartesian3(
    viewer,
    cartographic
  )
  return viewPointWebMercator
}

/**
 * 笛卡尔坐标转经纬度坐标
 * @param {Cartesian3} cartesian3 笛卡尔坐标
 * @param {String } cartographicType 经纬度坐标表示类型（Radians：弧度表示 Degrees：度表示）
 * @function cartesian3ToCartographic
 * @memberof Coordinate
 */
export const cartesian3ToCartographic = function (cartesian3, cartographicType = "Radians") {
  var cartographic;
  if (cartographicType == "Radians") {
    cartographic = Cesium.Cartographic.fromCartesian(cartesian3);
  } else if (cartographicType == "Degrees") {
    cartographic = Cesium.Cartographic.fromCartesian(cartesian3);
    cartographic = this.latitude(cartographic);
    // cartographic = Cesium.Cartographic.fromDegrees(point.lng, point.lat, point.alt);
  }
  return cartographic;
}

/**
 * @description: 方法描述 笛卡尔坐标批量转经纬度坐标
 * @param {*} cartesian3Arr 笛卡尔坐标数组
 * @param {*} cartographicType 经纬度坐标表示类型（Radians：弧度表示 Degrees：度表示）
 * @return {*}
 */
export const cartesian3ToCartographicMany = function (cartesian3Arr, cartographicType = "Degrees") {
  return cartesian3Arr.map((cartesian3) =>
    this.cartesian3ToCartographic(cartesian3, cartographicType)
  )
}

/**
 * @description: 方法描述 批量从经纬度数组获取世界坐标数组
 * @param {Array} points 经纬度数组 例如[[113.37264365, 23.10296901],[113.37264365, 23.10296901],[113.37264365, 23.10296901]]
 * @return {*} 返回世界坐标数组 例如[{"x":-2328476.77310197,"y":5388031.4763123235,"z":2487217.7412398118},{"x":-2328491.464629894,"y":5388025.188779467,"z":2487217.6088169324}]
 */
export const WGS84ArraysToCartesian3 = function (points) {
  return points.map((item) =>
    Cesium.Cartesian3.fromDegrees(item[0], item[1])
  )
}

/**
 * @description: 方法描述 批量的从经纬度数组转成笛卡尔坐标数组
 * @param {*}
 * @return {*}
 */
export const WGS84s_to_Cartesian3 = function (points) {
  return points.map((item) => this.WGS84_to_Cartesian3(item));
}

/**
 * @description: 方法描述  将世界坐标数组转成用于wfs查询的字符串
 * @param {Cartesian3 []} points 世界坐标数组 例如 [{"x":-2328476.77310197,"y":5388031.4763123235,"z":2487217.7412398118},{"x":-2328491.464629894,"y":5388025.188779467,"z":2487217.6088169324}]
 * @return {*} 返回用于wfs查询的字符串例如  113.37473621,23.10370166 113.37473647,23.1037024 113.37477098,23.10372272
 */
export const cartesian3sToWfsWGS84Stsring = function (points) {
  let p = points.map((point) => this.Cartesian3_to_WGS84(point));
  function wfsGeometry(polygon) {
    let _polygonPoints = "";
    for (let i = 0; i < polygon.length; i++) {
      _polygonPoints += polygon[i].lng + "," + polygon[i].lat + " ";
    }
    return _polygonPoints;
  }
  return wfsGeometry(p);
}

 /**
 * 经纬度坐标转换为笛卡尔坐标
 * @param {object} cartographic 经纬度坐标
 * @function cartographicToCartesian3
 * @memberof Coordinate
 */
export const cartographicToCartesian3 = function (cartographic) {
  var cartesian3;
  if (cartographic.longitude) {
    cartesian3 = Cesium.Cartesian3.fromRadians(
      cartographic.longitude,
      cartographic.latitude,
      cartographic.height
    );
  } else {
    cartesian3 = Cesium.Cartesian3.fromDegrees(
      cartographic.lng,
      cartographic.lat,
      cartographic.alt
    );
  }
  return cartesian3;
}

/**
 * 将以弧度表示的经纬度坐标转换为等效的Web Mercator X，Y，Z坐标（以米表示）
 * @param {object} viewer viewer
 * @param {*} cartographic 以弧度表示的经纬度坐标
 * @function cartographicToMercatorCartesian3
 * @memberof Coordinate
 */
export const cartographicToMercatorCartesian3 = function (viewer, cartographic) {
  var webMercatorProjection = new Cesium.WebMercatorProjection(
    viewer.scene.globe.ellipsoid
  );
  var cartesian3 = webMercatorProjection.project(cartographic);
  return cartesian3;
}

/**
 * 将以米为单位的Web Mercator X，Y坐标转换为Cartographic 包含大地的椭球坐标。
 * @param {object} viewer viewer
 * @param {*} cartesian 以米为单位的Web Mercator X，Y坐标
 * @function mercatorCartesian3ToCartographic
 * @memberof Coordinate
 */
export const mercatorCartesian3ToCartographic = function (viewer, cartesian) {
  var webMercatorProjection = new Cesium.WebMercatorProjection(
    viewer.scene.globe.ellipsoid
  );
  let cartographic = webMercatorProjection.unproject(cartesian);
  return cartographic;
}

/**
 * 将世界坐标转换成投影坐标
 * @param {object} viewer viewer
 * @param {object} cartesian3  坐标
 * @function cartesianToMercator
 * @memberof Coordinate
 */
export const cartesianToMercator = function (viewer, cartesian3) {
  var cartographic = Cesium.Cartographic.fromCartesian(cartesian3);
  var mercator = this.cartographicToMercatorCartesian3(viewer, cartographic);
  return mercator;
}

/**
 * 将投影坐标转换成世界坐标
 * @param {object} viewer viewer
 * @param {object} position 坐标
 * @function mercatorToCartesian
 * @memberof Coordinate
 */
export const mercatorToCartesian = function (viewer, position) {
  let viewPoint = new Cesium.Cartesian3(position.x, position.y, position.z);
  let cartographic = this.mercatorCartesian3ToCartographic(viewer, viewPoint);
  let point = this.latitude(cartographic);
  let cartesian = Cesium.Cartesian3.fromDegrees(
    point.lng,
    point.lat,
    point.alt
  );
  return cartesian;
}

/**
 * 根据弧度获取到经纬度
 * @param {object} cartographic 坐标
 * @function latitude
 * @memberof Coordinate
 */
export const latitude = function(cartographic) {
  var lat = Cesium.Math.toDegrees(cartographic.latitude);
  var lng = Cesium.Math.toDegrees(cartographic.longitude);
  var alt = cartographic.height;
  return {
    lng: lng,
    lat: lat,
    alt: alt,
  }
}

/**
 *
 * 修改笛卡尔点高度
 * @param {object} cartesian 坐标
 * @param {number} height 高度
 * @function changePointHeight
 * @memberof Coordinate
 */
export const changePointHeight = function (cartesian, height) {
  //将传入的笛卡尔点转换为经纬度高程点
  var position = this.cartesian3ToCartographic(cartesian, "Degrees");
  //将转换后的点高程换成传入的高度
  position.alt = height;
  return this.cartographicToCartesian3(position)
}

/**
 *
 * 修改笛卡尔点高度,当前高度增加相对高度
 * @param {object} cartesian 坐标
 * @param {number} height 高度
 * @function changePointHeight
 * @memberof Coordinate
 */
export const changePointAddHeight = function (cartesian, height) {
  //将传入的笛卡尔点转换为经纬度高程点
  var position = this.cartesian3ToCartographic(cartesian, "Degrees")
  //将转换后的点高程换成传入的高度
  position.alt += height;
  return this.cartographicToCartesian3(position);
}

/**
 *从度转换为弧度。
 * @param {number} radians 度
 * @function toRadians
 * @memberof Coordinate
 */
export const toRadians = function (degrees) {
  return (degrees * Math.PI) / 180
}

/**
 * 从弧度转换为度。
 * @param {number} radians 弧度
 * @function toDegrees
 * @memberof Coordinate
 */
export const toDegrees = function (radians) {
  return (radians * 180) / Math.PI
}

/**
 * @description: 方法描述 通用的坐标转换，传入世界坐标，经纬度，弧度坐标,4x4矩阵，屏幕坐标的某一种
 * 返回世界坐标，经纬度，弧度坐标
 * @param {Cartesian3/Matrix4/Cartographic/Cartesian2} coords 需要转换的坐标
 * @param {object} viewer viewer
 * @return {*} 返回世界坐标，经纬度，弧度坐标对象
 */
export const commomCoordinateTransform = function (coords, viewer) {
  let cartesian3, radians, degrees;
  if (coords instanceof Cesium.Cartesian3) {
    //传入的是世界坐标
    cartesian3 = coords;
    radians = this.cartesian3ToCartographic(coords, "Radians");
    degrees = this.cartesian3ToCartographic(coords, "Degrees");
  } else if (coords instanceof Cesium.Cartographic) {
    cartesian3 = this.cartographicToCartesian3(coords);
    radians = coords;
    degrees = this.cartesian3ToCartographic(cartesian3, "Degrees");
  } else if ("lat" in coords && "lng" in coords) {
    cartesian3 = this.cartographicToCartesian3(coords);
    radians = this.cartesian3ToCartographic(cartesian3, "Radians");
    degrees = coords;
  } else if (coords instanceof Cesium.Matrix4) {
    cartesian3 = Cesium.Matrix4.getTranslation(
      coords,
      new Cesium.Cartesian3()
    );
    radians = this.cartesian3ToCartographic(cartesian3, "Radians");
    degrees = this.cartesian3ToCartographic(cartesian3, "Degrees");
  } else if (coords instanceof Cesium.Cartesian2) {
    cartesian3 = this.screenToCartesian(viewer, coords);
    if (cartesian3) {
      radians = this.cartesian3ToCartographic(cartesian3, "Radians");
      degrees = this.cartesian3ToCartographic(cartesian3, "Degrees");
    }
  }
  return {
    cartesian3,
    radians,
    degrees,
  };
}

// 经度转换为瓦片x
export const lon2tilex = function (lon, zoom) {
  return Math.floor(((lon + 180) / 360) * Math.pow(2, zoom))
}

// 纬度转换为瓦片y
export const lat2tiley = function (lat, zoom) {
  return Math.floor(
    ((1 -
      Math.log(Math.tan((lat * Math.PI) / 180) + 1 / Math.cos((lat * Math.PI) / 180)) / Math.PI) /
      2) *
      Math.pow(2, zoom)
  )
}

// 墨卡托瓦片编号
export function getTileMercator (lon, lat, zoom) {
  return {
    x: Math.floor(((lon + 180) / 360) * Math.pow(2, zoom)),
    y: Math.floor(
      ((1 -
        Math.log(Math.tan((lat * Math.PI) / 180) + 1 / Math.cos((lat * Math.PI) / 180)) / Math.PI) /
        2) *
        Math.pow(2, zoom)
    )
  }
}

// 瓦片编号转经纬度，计算的是瓦片左上角的经纬度坐标，即西北方向，如果要计算东南方向的坐标则x和y各加1就行了
export function tile2lon(x, z) {
  return (x/Math.pow(2,z)*360-180);
}

export function tile2lat(y, z) {
  const n = Math.PI-2*Math.PI*y/Math.pow(2,z);
  return (180/Math.PI*Math.atan(0.5*(Math.exp(n)-Math.exp(-n))));
}

// 经纬度直投瓦片编号
export function getTileGeographic (l, b, zoom) {
  var n = parseInt(Math.pow(2, zoom));
  //计算每个瓦片单元的度数
  var cell = 360 / n;
  var x = parseInt(Math.floor((l + 180) / cell));
  var y = parseInt(Math.floor((b + 180) / cell));

  if (x < 0)
      x = 0;
  if (x >= n)
      x = parseInt(n - 1);

  if (y < 0)
      y = 0;
  if (y >= n)
      y = parseInt(n - 1);

  if (zoom > 1) {
      if (y >= n / 4 * 3)
          y = parseInt((n / 4 * 3) - 1);
      if (y < n / 4)
          y = parseInt(n / 4);
  }
  return { x, y }
}

const A = 40487.57;
const B = 0.00007096758;
const C = 91610.74;
const D = -40467.74;
// 高度转换为层级
export function heightToZoom (height) {
  var A = 40487.57
  var B = 0.00007096758
  var C = 91610.74
  var D = -40467.74
  return Math.round(D+(A-D)/(1+Math.pow(height/C, B)))
}

/**
 * 根据地图级别获取镜头高度
 * @param {Number} zoom
 */
export function zoomToHeight(zoom) {
  return Math.round(C * Math.pow((A - D) / (zoom - D) - 1, 1 / B))
}

/**
 * 计算a点和b点的角度（偏行角）
 * @param lng_a a点经度
 * @param lat_a a点维度
 * @param lng_b b点经度
 * @param lat_b b点维度
 * @returns 角度
 */
export const courseAngle = function (lng_a, lat_a, lng_b, lat_b) {
	//以a点为原点建立局部坐标系（东方向为x轴,北方向为y轴,垂直于地面为z轴），得到一个局部坐标到世界坐标转换的变换矩阵
	var localToWorld_Matrix = Cesium.Transforms.eastNorthUpToFixedFrame(new Cesium.Cartesian3.fromDegrees(lng_a, lat_a));
	//求世界坐标到局部坐标的变换矩阵
	var worldToLocal_Matrix = Cesium.Matrix4.inverse(localToWorld_Matrix, new Cesium.Matrix4());    	
	//a点在局部坐标的位置，其实就是局部坐标原点
  var localPosition_A = Cesium.Matrix4.multiplyByPoint(worldToLocal_Matrix, new Cesium.Cartesian3.fromDegrees(lng_a, lat_a), new Cesium.Cartesian3());
  //B点在以A点为原点的局部的坐标位置
  var localPosition_B = Cesium.Matrix4.multiplyByPoint(worldToLocal_Matrix, new Cesium.Cartesian3.fromDegrees(lng_b, lat_b), new Cesium.Cartesian3());
  //弧度
  var angle = Math.atan2((localPosition_B.y-localPosition_A.y), (localPosition_B.x-localPosition_A.x))
  //角度
  var theta = angle*(180/Math.PI);
  if (theta < 0) {
    theta = theta + 360;
  }
  return theta;
}

/**
 * 计算a点和b点的角度（俯仰角）
 * @param lng_a a点经度
 * @param lat_a a点维度
 * @param lng_b b点经度
 * @param lat_b b点维度
 * @returns 角度
 */
export const coursePitchAngle = function (lng_a, lat_a, alt_a, lng_b, lat_b, alt_b) {
	//以a点为原点建立局部坐标系（东方向为x轴,北方向为y轴,垂直于地面为z轴），得到一个局部坐标到世界坐标转换的变换矩阵
	var localToWorld_Matrix = Cesium.Transforms.eastNorthUpToFixedFrame(new Cesium.Cartesian3.fromDegrees(lng_a, lat_a, alt_a));
	//求世界坐标到局部坐标的变换矩阵
	var worldToLocal_Matrix = Cesium.Matrix4.inverse(localToWorld_Matrix, new Cesium.Matrix4());    	
	//a点在局部坐标的位置，其实就是局部坐标原点
  var localPosition_A = Cesium.Matrix4.multiplyByPoint(worldToLocal_Matrix, new Cesium.Cartesian3.fromDegrees(lng_a, lat_a, alt_a), new Cesium.Cartesian3());
  //B点在以A点为原点的局部的坐标位置
  var localPosition_B = Cesium.Matrix4.multiplyByPoint(worldToLocal_Matrix, new Cesium.Cartesian3.fromDegrees(lng_b, lat_b, alt_b), new Cesium.Cartesian3());
  //弧度
  var angle = Math.atan2((localPosition_B.z-localPosition_A.z), (localPosition_B.x-localPosition_A.x))
  //角度
  var theta = angle*(180/Math.PI);
  if (theta < 0) {
    theta = theta + 360;
  }
  return theta;
}
 
/**
 * 计算a点和b点的角度（俯仰角）
 * @param lng_a a点经度
 * @param lat_a a点维度
 * @param lng_b b点经度
 * @param lat_b b点维度
 * @returns 角度
 */
export const coursePitchAngleAlt = function (lng_a, lat_a, alt_a, lng_b, lat_b, alt_b) {
	//以a点为原点建立局部坐标系（东方向为x轴,北方向为y轴,垂直于地面为z轴），得到一个局部坐标到世界坐标转换的变换矩阵
	var localToWorld_Matrix = Cesium.Transforms.eastNorthUpToFixedFrame(new Cesium.Cartesian3.fromDegrees(lng_a, lat_a));
	//求世界坐标到局部坐标的变换矩阵
	var worldToLocal_Matrix = Cesium.Matrix4.inverse(localToWorld_Matrix, new Cesium.Matrix4());    	
	//a点在局部坐标的位置，其实就是局部坐标原点
  var localPosition_A = Cesium.Matrix4.multiplyByPoint(worldToLocal_Matrix, new Cesium.Cartesian3.fromDegrees(lng_a, lat_a), new Cesium.Cartesian3());
  //B点在以A点为原点的局部的坐标位置
  var localPosition_B = Cesium.Matrix4.multiplyByPoint(worldToLocal_Matrix, new Cesium.Cartesian3.fromDegrees(lng_b, lat_b), new Cesium.Cartesian3());
  let distance = Math.sqrt(Math.pow((localPosition_B.x-localPosition_A.x),2)+ Math.pow((localPosition_B.y-localPosition_A.y),2))
	let dz = alt_b - alt_a;
	var angle = 0;
	if(distance != 0){
		angle = Math.tanh(dz/distance);
	}
	var theta = angle*(180/Math.PI);
  return theta;
}

/**
 * 更新目标的位置及方位
 */
export const updateOrientation = function (targetEntity){
	var pathPosition = targetEntity.pathPosition;
	// 前一个坐标点
	var preIndex = 0;
	if(pathPosition.length > 1){
		preIndex = pathPosition.length-2;
	}
	var prevPosition = Cesium.Cartesian3.fromDegrees(pathPosition[preIndex][0], pathPosition[preIndex][1], pathPosition[preIndex][2]);
	// 当前坐标点
	var currentIndex = pathPosition.length-1;
	// var currentPosition = Cesium.Cartesian3.fromDegrees(pathPosition[currentIndex][0], pathPosition[currentIndex][1], pathPosition[currentIndex][2]);
 
	// 计算a点和b点的角度（偏行角）
	var angle = courseAngle(pathPosition[preIndex][0], pathPosition[preIndex][1],pathPosition[currentIndex][0], pathPosition[currentIndex][1]);
	angle = 360 - Number(angle.toFixed(0));
	// 计算a点和b点的角度（俯仰角）
	var pitchAngle = coursePitchAngle(pathPosition[currentIndex][0], pathPosition[currentIndex][1], pathPosition[currentIndex][2], pathPosition[preIndex][0], pathPosition[preIndex][1], pathPosition[preIndex][2]);
	pitchAngle = Number(pitchAngle.toFixed(0));
	if(pitchAngle > 180){
		pitchAngle = 360 - pitchAngle;
	}else{
		pitchAngle = 180 + pitchAngle;
	}
	// 根据“俯仰角、偏行角、滚转角”得到目标方位
	var gheading = Cesium.Math.toRadians(angle);
	var gpitch = Cesium.Math.toRadians(pitchAngle);
	var groll = Cesium.Math.toRadians(0);
	var hpr = new Cesium.HeadingPitchRoll(gheading, gpitch, groll);
	var orientation = Cesium.Transforms.headingPitchRollQuaternion(prevPosition, hpr);
	targetEntity.orientation = orientation;
}

/*
根据实体方位计算角度 
// 计算四元数
var _angle = targetEntity.orientation.getValue(viewer.clock.currentTime);
// 计算旋转角(弧度)
var hpr = Cesium.HeadingPitchRoll.fromQuaternion(_angle);
// 得到角度
var heading = Cesium.Math.toDegrees(hpr.heading);
var pitch = Cesium.Math.toDegrees(hpr.pitch);
var roll = Cesium.Math.toDegrees(hpr.roll);
console.log('heading : ' + heading, 'pitch : ' + pitch, 'roll : ' + roll);

*/
export const getHeading = function (pointA, pointB) {
  //建立以点A为原点，X轴为east,Y轴为north,Z轴朝上的坐标系
  const transform = Cesium.Transforms.eastNorthUpToFixedFrame(pointA);
  //向量AB
  const positionvector = Cesium.Cartesian3.subtract(pointB, pointA, new Cesium.Cartesian3());
  //因transform是将A为原点的eastNorthUp坐标系中的点转换到世界坐标系的矩阵
  //AB为世界坐标中的向量
  //因此将AB向量转换为A原点坐标系中的向量，需乘以transform的逆矩阵。
  const vector = Cesium.Matrix4.multiplyByPointAsVector(Cesium.Matrix4.inverse(transform, new Cesium.Matrix4()), positionvector, new Cesium.Cartesian3());
  //归一化
  const direction = Cesium.Cartesian3.normalize(vector, new Cesium.Cartesian3());
  //heading
  const heading = Math.atan2(direction.y, direction.x) - Cesium.Math.PI_OVER_TWO;
  return Cesium.Math.TWO_PI - Cesium.Math.zeroToTwoPi(heading);
}
export const getPitch = function (pointA, pointB) {
  let transfrom = Cesium.Transforms.eastNorthUpToFixedFrame(pointA);
  const vector = Cesium.Cartesian3.subtract(pointB, pointA, new Cesium.Cartesian3());
  let direction = Cesium.Matrix4.multiplyByPointAsVector(Cesium.Matrix4.inverse(transfrom, transfrom), vector, vector);
  Cesium.Cartesian3.normalize(direction, direction);
  //因为direction已归一化，斜边长度等于1，所以余弦函数等于direction.z
  return Cesium.Math.PI_OVER_TWO - Cesium.Math.acosClamped(direction.z);
}

export const getModelMatrix = function (pointA, pointB) {
  //向量AB
  const vector2 = Cesium.Cartesian3.subtract(pointB, pointA, new Cesium.Cartesian3());
  //归一化
  const normal = Cesium.Cartesian3.normalize(vector2, new Cesium.Cartesian3());
  //旋转矩阵 rotationMatrixFromPositionVelocity源码中有，并未出现在cesiumAPI中
  const rotationMatrix3 = Cesium.Transforms.rotationMatrixFromPositionVelocity(pointA, normal, Cesium.Ellipsoid.WGS84);
  // const orientation = Cesium.Quaternion.fromRotationMatrix(rotationMatrix3);
  const modelMatrix4 = Cesium.Matrix4.fromRotationTranslation(rotationMatrix3, pointA);
  //点B的模型矩阵
  //const modelMatrix4 = Cesium.Matrix4.fromRotationTranslation(rotationMatrix3, pointB);
  //const hpr = Cesium.HeadingPitchRoll.fromQuaternion(orientation);
  return modelMatrix4;
}

export const getOrientation = function (pointB, pointA, { pitch, roll, heading } = {}) {
  // let pointA =  Cesium.Cartesian3.fromDegrees(110,30,100);
  // let pointB =  Cesium.Cartesian3.fromDegrees(120,40,10000);

  let m = getModelMatrix(pointA, pointB);
  let hpr = getHeadingPitchRoll(m);
  if (pitch !== undefined) {
    hpr.pitch = pitch
  }
  if (roll !== undefined) {
    hpr.roll = roll
  }
  if (heading !== undefined) {
    hpr.heading = heading
  }
  let orientation = Cesium.Transforms.headingPitchRollQuaternion(
    pointA,
    hpr
  );
  return orientation
}

export const getHeadingPitchRoll = function (m) {
  var m1 = Cesium.Transforms.eastNorthUpToFixedFrame(
    Cesium.Matrix4.getTranslation(m, new Cesium.Cartesian3()),
    Cesium.Ellipsoid.WGS84,
    new Cesium.Matrix4()
  );
  // 矩阵相除
  var m3 = Cesium.Matrix4.multiply(
    Cesium.Matrix4.inverse(m1, new Cesium.Matrix4()),
    m,
    new Cesium.Matrix4()
  );
  // 得到旋转矩阵
  var mat3 = Cesium.Matrix4.getMatrix3(m3, new Cesium.Matrix3());
  // 计算四元数
  var q = Cesium.Quaternion.fromRotationMatrix(mat3);
  // 计算旋转角(弧度)
  var hpr = Cesium.HeadingPitchRoll.fromQuaternion(q);
  return hpr;
}

/**
 * 经纬度转度分秒
 * @param {经度/纬度}} lnglat
 */
export const lngLatToTSM = function (lnglat) {
  var index = lnglat.indexOf('.')
  var temp = index < 0 ? lnglat : lnglat.substring(0, index)
  var min = 0
  var sec = 0
  if (index > 0) {
    min = '0' + lnglat.substring(index)
    min = min * 60 + ''
    index = min.indexOf('.')
    if (index > 0) {
      sec = '0' + min.substring(index)
      min = min.substring(0, index)
      sec = sec * 60 + ''
      index = sec.indexOf('.')
      sec = sec.substring(0, index + 4)
      sec = parseFloat(sec).toFixed(2)
    }
  }
  return { temp, min, sec }
}

/**
 * 度分秒转经纬度
 * @param {度}} temp
 * @param {分} min
 * @param {秒} sec
 * @param {截取长度} len
 */
export const tsmToLnglat = function (temp, min, sec, len = 6) {
  temp = parseFloat(temp)
  min = parseFloat(min) / 60
  sec = parseFloat(sec) / 3600
  var lnglat = temp + min + sec
  return lnglat.toFixed(len)
}